package learn.io.nio.demo;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

interface FileCopyRunner {
    void copyFile(File source, File target);
}

public class FileCopyDemo {

    private static final int ROUNDS = 5;

    private static void benchmark(FileCopyRunner test, File source, File target) {
        long elapsed = 0L;
        for (int i = 0; i < ROUNDS; i++) {
            long start = System.currentTimeMillis();
            test.copyFile(source, target);
            elapsed += System.currentTimeMillis() - start;
            target.delete();
        }
    }

    public static void main(String[] args) {

        FileCopyRunner noBufferStreamCopy = (source, target) -> {
            try (InputStream fin = new FileInputStream(source);
                 OutputStream fout = new FileOutputStream(target)) {

                int result;
                while ((result = fin.read()) != -1) {
                    fout.write(result);
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {

            }
        };

        FileCopyRunner bufferedStreamCopy = (source, target) -> {
            try (InputStream fin = new BufferedInputStream(new FileInputStream(source));
                 OutputStream fout = new BufferedOutputStream(new FileOutputStream(target))) {
                byte[] buffer = new byte[1024];

                int result;
                while ((result = fin.read(buffer)) != -1) {
                    fout.write(buffer, 0, result);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        };

        FileCopyRunner nioBufferCopy = (source, target) -> {
            try (FileChannel fin = new FileInputStream(source).getChannel();
                 FileChannel fout = new FileInputStream(target).getChannel()) {

                ByteBuffer buffer = ByteBuffer.allocate(1024);
                while (fin.read(buffer) != -1) {
                    // buffer视为数据源
                    // 写模式 -> 读模式
                    buffer.flip();

                    while (buffer.hasRemaining()) {
                        fout.write(buffer);
                    }

                    // 读模式 -> 写模式
                    buffer.clear();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        };

        FileCopyRunner nioTransferCopy = (source, target) -> {
            try (FileChannel fin = new FileInputStream(source).getChannel();
                 FileChannel fout = new FileInputStream(target).getChannel()) {

                long transfered = 0L;
                while (transfered != fin.size()) {
                    transfered += fin.transferTo(0, fin.size(), fout);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        };
    }
}
